using System;
using NUnit.Framework;
using Pine.Core;
using Pine.Compiler.Utils;

namespace UnitTests
{
	[TestFixture]
	public class TestAPI
	{
		private static void AssertSingleResult(ValueList rl, Value value, string errorMessage) {
			Assert.AreEqual(1, rl.Size, errorMessage);
			Assert.AreEqual(value, rl.GetArrayElement(0), errorMessage);
		}
		
		[Test]
		public void TestArray() {
			ValueList rl = new ValueList();
			
			Compiler.ExecuteString("test-api-array-copy", "main", @"\main() { var x = [0=>1]; var y = x.copy(); y[0]++; return x[0]; }", rl, null);
			AssertSingleResult(rl, new Number(1), "Incorrect behavior for array copy");
			
			Compiler.ExecuteString("test-api-array-each", "main", @"\main() {
	var x = ['a'=>'b', 'c'=>'d', 'e'=>'f', 'g'=>'h'];
	var str = """";
	var last = ""FAIL"";
	var failure = ""FAIL"";
	failure:failure = x.each(""foo"");
	str = str + failure;
	last, failure:failure = x.each(\(key:k, value:v, 0:v2, index:i) {
		str = str + k + ' ' + v + ' ' + v2 + ' ' + i + '\n';
		return i, interrupt: k == 'e';
	});
	return str + last + ' ' + failure;
}", rl, null);
			AssertSingleResult(rl, new StringValue("truea b b 0\nc d d 1\ne f f 2\n2 false"), "Incorrect behavior for array each");
			
			Compiler.ExecuteString("test-api-array-copy", "main", @"\main() {
	var x = ['a'=>1,'b'=>2,'c'=>2];
	return x.find(2).toString() + x.find('z') + x.find(null);
}", rl, null);
			AssertSingleResult(rl, new StringValue("bnullnull"), "Incorrect behavior for array find");
			
			Compiler.ExecuteString("test-api-array-keys", "main", @"\main() {
	var x = ['a'=>1, 'b'=>2, 'c'=>3];
	var str = """";
	x.keys().each(\(key:key, value:val){ str = str + key + val; });
	return str;
}", rl, null);
			AssertSingleResult(rl, new StringValue("0a1b2c"), "Incorrect behavior for array keys");
			
			Compiler.ExecuteString("test-api-array-last", "main", @"\main() {
	var x = [1=>1, 2=>2, 3=>4];
	var key;
	x, key:key = x.last();
	return key + "" => "" + x + "", empty="" + [].last();
}", rl, null);
			AssertSingleResult(rl, new StringValue("3 => 4, empty=null"), "Incorrect behavior for array last");
			
			Compiler.ExecuteString("test-api-array-first", "main", @"\main() {
	var x = [1=>'a', 2=>2, 3=>4];
	var key;
	x, key:key = x.first();
	return key + "" => "" + x + "", empty="" + [].first();
}", rl, null);
			AssertSingleResult(rl, new StringValue("1 => a, empty=null"), "Incorrect behavior for array first");
			
			Compiler.ExecuteString("test-api-array-length", "main", @"\main() { return [].length().toString() + [1=>2,'b'=>'x'].length(); }", rl, null);
			AssertSingleResult(rl, new StringValue("02"), "Incorrect behavior for array length");
			
			Compiler.ExecuteString("test-api-array-pop", "main", @"\main() {
	var x = [1=>'a', 2=>'b', 3=>'c'];
	var key; var val; var fail;
	val, key:key, failure:fail = [].pop();
	if (val != null || key != null || !fail)
		return ""fail1"";
	val, key:key, failure:fail = x.pop();
	if (val != 'c' || key != 3 || fail)
		return ""fail2"";
	return x == [1=>'a', 2=>'b'];
}", rl, null);
			AssertSingleResult(rl, BooleanValue.True, "Incorrect behavior for array pop");
		}
	}
}

